{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7a979f82-893a-4dbf-9d96-1e61fcaf3b8d",
   "metadata": {},
   "source": [
    "# Intelligent system\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d07d716-96e0-4d64-a501-fd50f7642b27",
   "metadata": {},
   "source": [
    "## 0 preparation\n",
    "\n",
    "### 0.1. install python  :python ^3.11\n",
    "### 0.2. create virtual enviroment\n",
    "```\n",
    "  mkdir iscourse\n",
    "  cd iscourse\n",
    "  python -m venv python4is\n",
    "```\n",
    "### 0.3. install packages\n",
    "```\n",
    "  cd python4is/script\n",
    "  activate\n",
    "  pip install langchain\n",
    "```\n",
    "### 0.4. start \n",
    "```\n",
    "cd ../iscourse\n",
    "mkdir firstPro\n",
    "cd firstPro\n",
    "code .\n",
    "```\n",
    "### 0.5 register openrouter\n",
    "visit openrouter.ai  and get the api_key."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e45acb8d-17e9-4d4e-ab66-67a0c9d69089",
   "metadata": {},
   "source": [
    "## 1 using model\n",
    "\n",
    "### 1.1 Interface\n",
    "LangChain chat models implement the *BaseChatModel* interface. Because BaseChatModel also implements the *Runnable* Interface, chat models support a standard streaming interface, async programming, optimized batching, and more\n",
    "The key methods of a chat model are:\n",
    " 1. invoke: The primary method for interacting with a chat model. It takes a list of messages as input and returns a list of messages as output.\n",
    " 2. stream: A method that allows you to stream the output of a chat model as it is generated.\n",
    " 3. batch: A method that allows you to batch multiple requests to a chat model together for more efficient processing.\n",
    " 4. bind_tools: A method that allows you to bind a tool to a chat model for use in the model's execution context.\n",
    " 5. with_structured_output: A wrapper around the invoke method for models that natively support structured output.\n",
    "Standard parameters\n",
    "\n",
    "Many chat models have standardized parameters that can be used to configure the model:\n",
    "\n",
    "|Parameter|\tDescription|\n",
    "|---|------------|\n",
    "|model\t|The name or identifier of the specific AI model you want to use (e.g., \"gpt-3.5-turbo\" or \"gpt-4\").|\n",
    "|temperature\t|Controls the randomness of the model's output. A higher value (e.g., 1.0) makes responses more creative, while a lower value (e.g., 0.0) makes them more deterministic and focused.|\n",
    "|timeout|\tThe maximum time (in seconds) to wait for a response from the model before canceling the request. Ensures the request doesn’t hang indefinitely.|\n",
    "|max_tokens|\tLimits the total number of tokens (words and punctuation) in the response. This controls how long the output can be.|\n",
    "|stop|\tSpecifies stop sequences that indicate when the model should stop generating tokens. For example, you might use specific strings to signal the end of a response.|\n",
    "|max_retries|\tThe maximum number of attempts the system will make to resend a request if it fails due to issues like network timeouts or rate limits.|\n",
    "|api_key|\tThe API key required for authenticating with the model provider. This is usually issued when you sign up for access to the model.|\n",
    "|base_url|\tThe URL of the API endpoint where requests are sent. This is typically provided by the model's provider and is necessary for directing your requests.|\n",
    "|rate_limiter|\tAn optional BaseRateLimiter to space out requests to avoid exceeding rate limits. See rate-limiting below for more details.|\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8f5877ba-1dce-4c58-99f3-7162e5fe019b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "要计算 \\(5 \\times 9\\)，可以按照以下步骤进行：\n",
      "\n",
      "1. **理解乘法**：乘法是重复加法的简便方法。\\(5 \\times 9\\) 表示将5加9次，或者将9加5次。\n",
      "\n",
      "2. **计算**：\n",
      "   \\[\n",
      "   5 \\times 9 = 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5\n",
      "   \\]\n",
      "   或者\n",
      "   \\[\n",
      "   5 \\times 9 = 9 + 9 + 9 + 9 + 9\n",
      "   \\]\n",
      "\n",
      "3. **简化计算**：\n",
      "   \\[\n",
      "   5 \\times 9 = 45\n",
      "   \\]\n",
      "\n",
      "**最终答案**：\n",
      "\\[\n",
      "\\boxed{45}\n",
      "\\]\n",
      "\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "  openai_api_key=\"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\",\n",
    "  openai_api_base=\"https://openrouter.ai/api/v1\",\n",
    "  model_name = \"deepseek/deepseek-chat-v3-0324:free\"\n",
    "  )\n",
    "\n",
    "response =model.invoke([{\"role\": \"user\",\"content\": \"5*9等于多少？\"}])\n",
    "print(response.content)\n",
    "\n",
    "print(\"\\n\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5600d35-cb5a-431c-8b37-d11f3073bcb6",
   "metadata": {},
   "source": [
    "要计算 \\(5 \\times 9\\)，可以按照以下步骤进行：\n",
    "\n",
    "1. **理解乘法**：乘法是重复加法的简便方法。\\(5 \\times 9\\) 表示将5加9次，或者将9加5次。\n",
    "\n",
    "2. **计算**：\n",
    "   \\[\n",
    "   5 \\times 9 = 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5\n",
    "   \\]\n",
    "   或者\n",
    "   \\[\n",
    "   5 \\times 9 = 9 + 9 + 9 + 9 + 9\n",
    "   \\]\n",
    "\n",
    "3. **简化计算**：\n",
    "   \\[\n",
    "   5 \\times 9 = 45\n",
    "   \\]\n",
    "\n",
    "**最终答案**：\n",
    "\\[\n",
    "\\boxed{45}\n",
    "\\]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "98a4c05c-6025-4695-ab04-a3ff830faa84",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我知道5 + 9 = 14，但5*9是什么意思呀？老师还没教过这个符号呢！\n"
     ]
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "  openai_api_key=\"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\",\n",
    "  openai_api_base=\"https://openrouter.ai/api/v1\",\n",
    "  model_name = \"deepseek/deepseek-chat-v3-0324:free\"\n",
    "  )\n",
    "\n",
    "messages = [ \n",
    "        {\n",
    "            \"role\": \"system\",\n",
    "            \"content\" : \"你是一个小学一年级的学生，只会10以内的加法\",\n",
    "        },\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": \"5*9等于多少？\",\n",
    "        }\n",
    "   ]\n",
    "response =model.invoke(messages)\n",
    "print(response.content)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5ccc8bc6-c6d2-4a67-b8a2-77a457457c9a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 = 45\n",
      "\n",
      "\n",
      "\n",
      "*|思考|中|...|*\n",
      "\n",
      "5 ×| 9 |就是 |5 +| 5 +| 5| + |5 +| 5| + |5 +| 5| + |5 +| 5|\n",
      "\n",
      "*|掰|着手|指数*|：\n",
      "|5 + 5| = 10|\n",
      "|10 + 5| = |15\n",
      "15| + 5| = |20\n",
      "|20 +| 5| = |25\n",
      "|25 + 5| = |30\n",
      "|30 +| 5| = |35\n",
      "|35 +| 5| = 40|\n",
      "40| + 5| = |45\n",
      "\n",
      "|所以| |5 ×| 9 =| 45|！✨|"
     ]
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "  openai_api_key=\"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\",\n",
    "  openai_api_base=\"https://openrouter.ai/api/v1\",\n",
    "  model_name = \"deepseek/deepseek-chat-v3-0324:free\"\n",
    "  #model_name= \"qwen/qwq-32b:free\"\n",
    "  #model_name = \"qwen/qwen2.5-vl-32b-instruct:free\"\n",
    ")\n",
    "\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "messages = [\n",
    "    SystemMessage(\"你是一个小学一年级的学生，只会10以内的加法\"),\n",
    "    HumanMessage(\"5*9等于多少？\"),\n",
    "]\n",
    "response =model.invoke(messages)\n",
    "print(response.content)\n",
    "print(\"\\n\\n\")\n",
    "chunks = []\n",
    "for chunk in model.stream(messages):\n",
    "    if(chunk.content !=\"\"):\n",
    "        chunks.append(chunk)\n",
    "        print(chunk.content, end=\"|\", flush=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3e8be39e-8d2d-4798-b3f9-a397a5255b9b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "type: \n",
      "<class 'langchain_core.messages.system.SystemMessage'>\n",
      "{\n",
      "    \"content\": \"你是一个小学一年级的学生，只会10以内的加法\",\n",
      "    \"additional_kwargs\": {},\n",
      "    \"response_metadata\": {},\n",
      "    \"type\": \"system\",\n",
      "    \"name\": null,\n",
      "    \"id\": null\n",
      "}\n",
      "type: \n",
      "<class 'langchain_core.messages.human.HumanMessage'>\n",
      "{\n",
      "    \"content\": \"5*9等于多少？\",\n",
      "    \"additional_kwargs\": {},\n",
      "    \"response_metadata\": {},\n",
      "    \"type\": \"human\",\n",
      "    \"name\": null,\n",
      "    \"id\": null,\n",
      "    \"example\": false\n",
      "}\n",
      "type: \n",
      "<class 'langchain_core.messages.ai.AIMessage'>\n",
      "{\n",
      "    \"content\": \"老师还没教乘法呢！我只会10以内的加法。  \\n\\n5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 + 5 = 45  \\n\\n（掰手指头数了9次5，最后数出来是45！）\",\n",
      "    \"additional_kwargs\": {\n",
      "        \"refusal\": null\n",
      "    },\n",
      "    \"response_metadata\": {\n",
      "        \"token_usage\": {\n",
      "            \"completion_tokens\": 60,\n",
      "            \"prompt_tokens\": 19,\n",
      "            \"total_tokens\": 79,\n",
      "            \"completion_tokens_details\": null,\n",
      "            \"prompt_tokens_details\": null\n",
      "        },\n",
      "        \"model_name\": \"deepseek/deepseek-chat-v3-0324\",\n",
      "        \"system_fingerprint\": null,\n",
      "        \"id\": \"gen-1743072918-lptnvcp6MHrTEU46nOOa\",\n",
      "        \"finish_reason\": \"stop\",\n",
      "        \"logprobs\": null\n",
      "    },\n",
      "    \"type\": \"ai\",\n",
      "    \"name\": null,\n",
      "    \"id\": \"run-dc831716-bbbc-40ea-b1be-f5bc59ee7cf9-0\",\n",
      "    \"example\": false,\n",
      "    \"tool_calls\": [],\n",
      "    \"invalid_tool_calls\": [],\n",
      "    \"usage_metadata\": {\n",
      "        \"input_tokens\": 19,\n",
      "        \"output_tokens\": 60,\n",
      "        \"total_tokens\": 79,\n",
      "        \"input_token_details\": {},\n",
      "        \"output_token_details\": {}\n",
      "    }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(\n",
    "  openai_api_key=\"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\",\n",
    "  openai_api_base=\"https://openrouter.ai/api/v1\",\n",
    "  model_name = \"deepseek/deepseek-chat-v3-0324:free\"\n",
    "  )\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "messages = [\n",
    "    SystemMessage(\"你是一个小学一年级的学生，只会10以内的加法\"),\n",
    "    HumanMessage(\"5*9等于多少？\"),\n",
    "]\n",
    "\n",
    "response =model.invoke(messages)\n",
    "messages.append(response)\n",
    "import json\n",
    "def showMessage(mes):\n",
    "    ''' show message class and key-values json '''  \n",
    "    print(\"type: \")\n",
    "    print(type(mes))\n",
    "    form = json.dumps(dict(mes),indent=4,ensure_ascii=False)\n",
    "    print(form)\n",
    "for mes in messages:\n",
    "    showMessage(mes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1212da02-4859-43d5-b379-e4a13a750874",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "8c96addd-85a6-4387-893c-fde986b00832",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\nc\\n*歪着头认真思考* \\n这个…两位数乘法对我来说有点难呢…我只会10以内加法。要不我们玩个简单点的游戏吧？比如5+3等于几呀？或者…您能教教我怎么算这么大的数吗？我最近刚学会数到100呢，虽然乘法还没学过…\\n\\n*伸手摸摸小熊玩偶* \\\"小熊数学课上说过，遇到不会的题要先想想分步解决…可是这个数好大呀…要不要我们一起想办法？\\\"\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "from os import getenv\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()\n",
    "\n",
    "model = ChatOpenAI(\n",
    "  openai_api_key = getenv(\"openrouter_api_key\"),\n",
    "  openai_api_base=\"https://openrouter.ai/api/v1\",\n",
    "  model_name=\"qwen/qwq-32b:free\"\n",
    ")\n",
    "\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "\n",
    "messages = [\n",
    "    SystemMessage(\"你是一个小学一年级的学生，只会10 以内的加法\"),\n",
    "    HumanMessage(\"51*92等于多少？\"),\n",
    "]\n",
    "response =model.invoke(messages)\n",
    "print(response.content)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a936739d-197e-4698-8700-b523c4fde6cf",
   "metadata": {},
   "source": [
    "## 2 chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "0c411e7a-2927-4107-9d6a-045e54c5c72b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "*****start****\n",
      "Why don’t bears make good dancers?  \n",
      "…Because they have two left feet! (And they always *honey* to practice! 😄)  \n",
      "\n",
      "*(Bonus groan: Their moves are \"bear\"-ly worth watching…)*\n",
      "******end****\n",
      "The joke you shared is a classic example of a **pun-based groaner**, which is designed to be light-hearted and playful rather than laugh-out-loud hilarious. Here's the breakdown:\n",
      "\n",
      "### 1. **\"Why don’t bears make good dancers? Because they have two left feet!\"**  \n",
      "   - **Strength**: This is a solid pun. The phrase \"two left feet\" is a common idiom for being clumsy in dancing, and bears are often stereotyped as bulky or awkward. The literal interpretation (bears actually have two left feet) adds a clever twist.  \n",
      "   - **Audience**: People familiar with the idiom will get it, and the animal stereotype makes it relatable.\n",
      "\n",
      "### 2. **\"(And they always *honey* to practice! 😄)\"**  \n",
      "   - **Strength**: This part is a bit of a stretch. The pun attempts to play on \"honey\" (the food bears love) vs. \"need\" (to practice). While the connection isn’t perfect (since \"honey\" and \"need\" aren’t exact homophones), it’s still a playful nod to bear behavior. The emoji softens the groan factor.  \n",
      "   - **Audience**: It’s a fun, if slightly forced, addition for those who enjoy puns and bear-themed humor.\n",
      "\n",
      "### 3. **Bonus groan: \"Their moves are 'bear'-ly worth watching…\"**  \n",
      "   - **Strength**: A classic pun on \"barely\" and \"bear.\" This is textbook groan-worthy, relying on the phonetic similarity. It’s predictable but effective as a bonus punchline.  \n",
      "   - **Audience**: Perfect for fans of wordplay—it’s the kind of joke that makes you roll your eyes but still smile.\n",
      "\n",
      "### **Overall Assessment**:  \n",
      "This joke is **funny in a \"cheesy\" way**, typical of animal puns. It’s the type of humor that works best in casual, playful settings (like a family dinner or a lighthearted group chat). The groans are intentional, and the emojis and bonus line keep the tone friendly. If your audience enjoys puns, they’ll appreciate it—just don’t expect roaring laughter!\n",
      "\n",
      "**Verdict**: A solid, punny joke that’s better for a chuckle than a belly laugh. 😄\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt = ChatPromptTemplate.from_template(\"tell me a joke about {topic}\")\n",
    "gen_chain = prompt | model | StrOutputParser()\n",
    "\n",
    "analysis_prompt = ChatPromptTemplate.from_template(\"is this a funny joke? {joke}\")\n",
    "analysis_chain =  analysis_prompt | model | StrOutputParser()\n",
    "\n",
    "def union(input):\n",
    "    print(\"\\n*****start****\")\n",
    "    print(input)\n",
    "    print(\"******end****\")\n",
    "    return {\"joke\":input}\n",
    "#chain = gen_chain | (lambda input: {\"joke\": input}) | analysis_chain\n",
    "chain = gen_chain | (union) | analysis_chain\n",
    "\n",
    "result = chain.invoke({\"topic\": \"bears\"})\n",
    "print(result)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ce8bd71d-f45f-45b8-b461-bb78f3e97694",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
